class glspace cardpath parent labels labelsc path scale =
  let ev = GBin.event_box
            ~packing:parent
             ()
  in
  let realscale = ref (1./.scale)
  in
  let glw = GlGtk.area
              ~width:500
              ~height:300
              ~packing:ev#add
              ~show:true
              [`RGBA;`DOUBLEBUFFER; `BUFFER_SIZE(8); `DEPTH_SIZE(16)]
              ()
  in
  let convolve_point x y =
    let fl lx ly =
      Hashtbl.find labelsc (abs(labels.(lx).(ly)))
    in
    let (r,g,b) as col1 = fl x y
    in
    if not(x <= 3 || y <=3 ||
           x>(Array.length labels)-4 ||
           y > (Array.length labels.(0))-4) then
      begin
        let rf = ref r
        and gf = ref g
        and bf = ref b
        in
          for i=(x-1) to (x+1) do
            for j=(y-1) to (y+1) do
              let (rij,gij,bij) = fl i j
              in
                rf := !rf +. rij;
                gf := !gf +. gij;
                bf := !bf +. bij
            done
          done;
          (!rf /. 9.,!gf /. 9.,!bf /. 9.)
      end
    else
      col1
  in
  let (gl_display,gl_reshape,gl_init,
       gl_key,gl_mousemove,gl_mousemove_passive,
       gl_set_pos,gl_get_pos,gl_set_dir,
       gl_get_dir,gl_set_wire,gl_reload,
       gl_set_dp,gl_set_mod,gl_cam_moving,
       gl_set_speed) =
    (Glcalls.init_and_get
       500 300 cardpath
       (fun (x,y)->labels.(int_of_float
                             (x*.(!realscale))).(
                               int_of_float (y*.(!realscale))) < 0)
       (fun (x,y) -> convolve_point
                       (int_of_float (x*.(!realscale)))
                       (int_of_float (y*.(!realscale)))))
  in
  let idlelist = ref [] in

object(self)
  val evwin = ev
  val glwin = glw
  val mutable hasfocus = false
  val mutable hasmousefocus = false
  val mutable w = 500
  val mutable h = 300
  val mutable poschange = fun _ _ _ -> ()
  val mutable loosefocus = fun () -> ()

  method hasfocus = hasfocus
  method get_w () = w
  method get_h () = h


  method best_show (r,bbc) =
    self#show_vect true (r,bbc)
      (
          Geometry.mult (-.1.)
          (Geometry.normalized (Geometry.fromC3 (
            (gl_get_dir ())))
          )
        )

  method set_sel_mod mode =
    gl_set_mod mode

  method set_wired w =
    gl_set_wire w

  method set_speed sp =
    gl_set_speed sp

  method reload_infos newscale () =
    realscale:=1./.newscale;
    gl_reload cardpath

  method set_pos_dir (pos,dir) =
      gl_set_dp false pos dir

  method get_dir =
    let (dx,dy,dz) = gl_get_dir ()
    in
    let (x,y,z) = gl_get_pos ()
    in
      ((dx*.1000.)+.x,(dy*.1000.)+.y,(dz*.1000.)+.z)
  method show_r (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=1.;Geometry.y=0.;Geometry.z=0.}

  method show_up (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=0.;Geometry.y=1.;Geometry.z=0.}

  method show_l (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=(-1.);Geometry.y=0.;Geometry.z=0.}

  method show_down (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=0.;Geometry.y=(-1.);Geometry.z=0.}

  method show_back (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=0.;Geometry.y=(0.);Geometry.z=(-1.)}

  method show_front (r,bbc) =
    self#show_vect false (r,bbc)
      {Geometry.x=0.;Geometry.y=0.;Geometry.z=1.}
  method show_center ((_:float),bbc) =
        gl_set_dp true (Geometry.toC3 bbc) (0.,0.,0.)

  method show_vect norotate (r,bbc) vect =
    let dir =
     Geometry.add bbc (
      Geometry.mult r (
        vect
      )
     )
    in
    let (bbx,bby,bbz) = (Geometry.toC3 bbc)
    in
      gl_set_dp norotate (Geometry.toC3 dir) (bbx-.1.,bby-.1.,bbz-.1.)

  method set_position pos animate =
    if animate then
        gl_set_dp true pos (0.,0.,0.)
    else
      gl_set_pos pos;
    self#installdrawcallback_volatile ();
      ()

  method set_direction dir =
    gl_set_dir dir;
    self#installdrawcallback_volatile ();
      ()

  method gl_display  () =
    glwin#make_current ();
    let forwardpos = gl_cam_moving ()
    in
    gl_display ();
    if forwardpos then
      poschange 0 (gl_get_pos ()) false;
    glwin#swap_buffers ()


  method gl_reshape ~width ~height =
    w <- width;
    h <- height;
    glwin#make_current ();
    gl_reshape width height;
    self#gl_display ()

  method gl_init () =
    glwin#make_current ();
    gl_init ()

  method kill_draw_no_focus ()=
    self#releaseidles !idlelist;
    idlelist := []
  method reset_draw_focus ()=
    idlelist := GMain.Idle.add
                  (fun () -> (self#gl_display ());true)::!idlelist


  method keypress ev =
    gl_key (GdkEvent.Key.hardware_keycode ev);
    poschange 0 (gl_get_pos ()) false

  method releaseidles li =
    let rec call l =
      match l with
      [] -> ()
    | e::q -> GMain.Idle.remove e; call q
    in
      call li

  method setfocus =
    hasfocus <- true;
    hasmousefocus <- true

  method resetfocus = hasfocus <- false

  method resetmousefocus = hasmousefocus <- false

  method installdrawcallback_volatile () =
    evwin#misc#grab_focus ();
    loosefocus ()
  method installdrawcallback () =
    evwin#misc#grab_focus ();
    loosefocus ()

  method focus_out _ =
    hasmousefocus <- false;
    hasfocus <- false;
    loosefocus ();
    true

  method init poschcallback loosefocus_call () =
    poschange <- poschcallback;
    evwin#event#add [`POINTER_MOTION];
    evwin#event#add [`BUTTON_PRESS];
    evwin#event#add [`BUTTON_RELEASE];
    evwin#event#add [`KEY_PRESS];
    evwin#event#add [`KEY_RELEASE];
    loosefocus <- loosefocus_call;
    ignore(evwin#event#connect#focus_out ~callback:self#focus_out);
    evwin#misc#set_can_focus true;
    ignore(glwin#connect#realize ~callback:self#gl_init);
    ignore(glwin#connect#reshape ~callback:self#gl_reshape);
    ignore(evwin#event#connect#motion_notify
             ~callback:(fun ev ->
                          let x = ((GdkEvent.Motion.x ev))
                          and y = ((GdkEvent.Motion.y ev)) in
                            if hasmousefocus then

                              gl_mousemove x y
                            else
                              gl_mousemove_passive x y;
                            true));
    ignore(evwin#event#connect#button_press
             ~callback:(fun _ ->
                          (self#installdrawcallback
                             ());
                          self#setfocus; true));
    ignore(evwin#event#connect#button_release
             ~callback:(fun ev ->
                          self#resetmousefocus;
                          true));
    ignore(evwin#event#connect#key_press
             ~callback:(fun ev ->
                          (self#installdrawcallback ());
                          self#keypress ev; true));
    ignore(evwin#event#connect#key_release ~callback:(fun ev -> true));
    glwin#connect#display ~callback:(fun _ -> self#gl_display ();() );
end
